package cn.ibdsr.human.constant;

import cn.ibdsr.human.core.check.Verfication;
import cn.ibdsr.human.db.model.BaseDTO;
import cn.ibdsr.human.exception.CheckDtoException;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @description:
 * @author: cdl
 * @email: iamcimon@qq.com
 * @date: 2021/8/2 13:29
 */
public class StaticCheck {
    private static final Logger LOGGER = LoggerFactory.getLogger(StaticCheck.class);

    public StaticCheck() {
    }

    public static void check(Object obj) {
        check(obj, true);
    }

    public static void check(Object obj, boolean isInsert) throws CheckDtoException {
        try {
            Map<String, Field> fieldMap = new HashMap();
            setClassFields(fieldMap, obj);
            PropertyDescriptor[] pds = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors();
            PropertyDescriptor[] var4 = pds;
            int var5 = pds.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                PropertyDescriptor pd = var4[var6];
                Field field = (Field)fieldMap.get(pd.getName());
                if (field != null) {
                    Object fieldValue = pd.getReadMethod().invoke(obj);
                    if (isInsert || fieldValue != null) {
                        Verfication v = (Verfication)field.getAnnotation(Verfication.class);
                        checkAll(v, fieldValue, obj, field, isInsert);
                    }
                }
            }

        } catch (InvocationTargetException | IllegalAccessException | IntrospectionException var11) {
            LOGGER.error("DTO校验异常，原因是".concat(var11.getMessage()), var11);
            throw new CheckDtoException(GunsExceptionEnum.SYSTEM_ERROR_INKNIWN_REASON);
        }
    }

    private static void checkAll(Verfication v, Object fieldValue, Object obj, Field field, boolean isInsert) {
        checkNotNull(v, fieldValue, field);
        checkStr(v, fieldValue, field);
        checkEmptyList(v, fieldValue, field);
        checkRange(v, fieldValue, field);
        checkForeign(v, fieldValue);
        checkUnique(v, fieldValue, obj, isInsert);
    }

    private static void checkUnique(Verfication v, Object fieldValue, Object obj, boolean isInsert) {
        String vName = v.name();
        String unique = v.unique();
        Class<? extends Model> modelClass = v.entity();
        BaseDTO baseDTO = (BaseDTO)obj;
        if (!StringUtils.isEmpty(unique) && modelClass.getSuperclass().equals(Model.class)) {
            try {
                QueryWrapper<Model> wrapper = getWrapper((Model)modelClass.newInstance(), fieldValue, unique);
                if (!isInsert) {
                    Long id = baseDTO.getId();
                    wrapper.ne("id", id);
                }

                Model model = (Model)modelClass.newInstance();
                List<Model> models = model.selectList(wrapper);
                if (!models.isEmpty()) {
                    throw new CheckDtoException(401, vName + "已存在！");
                }
            } catch (IllegalAccessException var11) {
                LOGGER.error("唯一性校验失败，原因是".concat(var11.getMessage()), var11);
                throw new CheckDtoException(GunsExceptionEnum.SYSTEM_ERROR_INKNIWN_REASON);
            } catch (InstantiationException var12) {
                LOGGER.error("唯一性校验失败，原因是".concat(var12.getMessage()), var12);
                throw new CheckDtoException(GunsExceptionEnum.SYSTEM_ERROR_INKNIWN_REASON);
            }
        }

    }

    private static QueryWrapper<Model> getWrapper(Model model, Object fieldValue, String column) {
        Field[] fields = model.getClass().getDeclaredFields();
        QueryWrapper<Model> wrapper = new QueryWrapper();
        wrapper.eq(column, fieldValue);
        boolean isDeleted = false;
        Field[] var6 = fields;
        int var7 = fields.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            Field field = var6[var8];
            if (field.getName().equals("isDeleted")) {
                isDeleted = true;
                break;
            }
        }

        if (isDeleted) {
            wrapper.eq("is_deleted", IsDeleted.NORMAL.getCode());
        }

        return wrapper;
    }

    private static void checkForeign(Verfication v, Object fieldValue) {
        String vName = v.name();
        Class<? extends Model> modelClass = v.forenign();
        if (fieldValue != null && modelClass.getSuperclass().equals(Model.class)) {
            try {
                Model model = (Model)modelClass.newInstance();
                Wrapper<Model> wrapper = getWrapper(model, fieldValue, "id");
                Model Do = model.selectOne(wrapper);
                if (Do == null) {
                    throw new CheckDtoException(401, vName + "不存在！");
                }
            } catch (CheckDtoException var7) {
                throw new CheckDtoException(401, vName + "不存在！");
            } catch (Exception var8) {
                throw new CheckDtoException(GunsExceptionEnum.SYSTEM_ERROR_INKNIWN_REASON);
            }
        }

    }

    private static void checkRange(Verfication v, Object fieldValue, Field field) {
        if (fieldValue != null) {
            try {
                int value = 2147483647;
                if (field.getType().equals(Integer.class)) {
                    value = (Integer)fieldValue;
                } else if (field.getType().equals(Long.class)) {
                    value = (new Long(fieldValue.toString())).intValue();
                } else if (field.getType().equals(Double.class)) {
                    value = (new Double(fieldValue.toString())).intValue();
                } else if (field.getType().equals(BigDecimal.class)) {
                    value = (new BigDecimal(fieldValue.toString())).intValue();
                }

                checkMinMax(v, value);
            } catch (NumberFormatException var4) {
                var4.printStackTrace();
                throw new CheckDtoException(GunsExceptionEnum.SYSTEM_ERROR_INKNIWN_REASON);
            }
        }

    }

    private static void checkMinMax(Verfication v, int value) {
        String vName = v.name();
        int max = v.max();
        if (max < 2147483647 && value > max) {
            throw new CheckDtoException(401, vName + "不能大于" + max + "！");
        } else {
            int min = v.min();
            if (min > -2147483648 && value < min) {
                throw new CheckDtoException(401, vName + "不能小于" + min + "！");
            }
        }
    }

    private static void checkEmptyList(Verfication v, Object fieldValue, Field field) {
        String vName = v.name();
        boolean vNotEmptyList = v.notEmptyList();
        if (List.class.isAssignableFrom(field.getType())) {
            List fieldValueList = (List)fieldValue;
            if (vNotEmptyList && (fieldValueList == null || fieldValueList.isEmpty())) {
                throw new CheckDtoException(401, vName + "不能为空List！");
            }
        }

    }

    private static void checkStr(Verfication v, Object fieldValue, Field field) {
        if (field.getType() != null && field.getType().equals(String.class)) {
            checkStrLen(v, fieldValue);
            checkStrRegx(v, fieldValue);
        }

    }

    private static void checkStrRegx(Verfication v, Object fieldValue) {
        String vName = v.name();
        String fieldValueStr = (String)fieldValue;
        String[] vRegx = v.regx();
        if (vRegx != null && vRegx.length == 2 && !StringUtils.isEmpty(fieldValueStr) && !Pattern.compile(vRegx[0]).matcher(fieldValueStr).matches()) {
            throw new CheckDtoException(401, vName + vRegx[1] + "！");
        }
    }

    private static void checkStrLen(Verfication v, Object fieldValue) {
        String vName = v.name();
        String str = (String)fieldValue;
        if (v.maxlength() > 0 && str != null && str.length() > v.maxlength()) {
            throw new CheckDtoException(401, vName + "不能超过" + v.maxlength() + "个字符！");
        } else if (v.minlength() > 0 && str != null && str.length() < v.minlength()) {
            throw new CheckDtoException(401, vName + "不能小于" + v.minlength() + "个字符！");
        }
    }

    private static void checkNotNull(Verfication v, Object fieldValue, Field field) {
        String vName = v.name();
        boolean vNotNull = v.notNull();
        if (vNotNull && fieldValue == null) {
            throw new CheckDtoException(401, vName + "不能为空！");
        } else if (vNotNull && field.getType().equals(String.class) && StringUtils.isBlank((String)fieldValue)) {
            throw new CheckDtoException(401, vName + "不能为空！");
        }
    }

    private static void setClassFields(Map<String, Field> fieldMap, Object obj) {
        Class superclass = obj.getClass();

        do {
            Field[] fields = superclass.getDeclaredFields();
            Field[] var4 = fields;
            int var5 = fields.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Field field = var4[var6];
                Verfication annotation = (Verfication)field.getAnnotation(Verfication.class);
                if (annotation != null) {
                    fieldMap.put(field.getName(), field);
                }
            }

            superclass = superclass.getSuperclass();
        } while(superclass != null && superclass != Object.class);

    }

    public static int getStringActualLength(String str) {
        if (isBlank(str)) {
            return 0;
        } else {
            int length = 0;

            for(int i = 0; i < str.length(); ++i) {
                if (isChineseChar(str.charAt(i))) {
                    length += 2;
                } else if (isFullSpaceChar(str.charAt(i))) {
                    length += 2;
                } else {
                    ++length;
                }
            }

            return length;
        }
    }

    private static boolean isBlank(String str) {
        if (str == null) {
            return true;
        } else {
            return str.trim().length() == 0;
        }
    }

    private static boolean isFullSpaceChar(char ch) {
        return ch >= '\uff00' && ch <= '\uffff';
    }

    private static boolean isChineseChar(char str) {
        return str >= 19968 && str <= '龻';
    }
}
